package de.gameduell.framework.game.billard.view {
	import sandy.core.Scene3D;
	import sandy.core.scenegraph.Camera3D;
	import sandy.core.scenegraph.Group;
	import sandy.materials.Appearance;
	import sandy.materials.BitmapMaterial;
	import sandy.materials.Material;
	import sandy.primitive.Sphere;
	
	import de.gameduell.framework.gui.wrapper.SpriteWrapper;
	import de.gameduell.framework.util.Library;
	
	import org.cove.ape.Quaternion;
	import org.cove.ape.Vector;
	import org.cove.ape.Vector3f;
	
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.errors.IllegalOperationError;
	import flash.events.Event;	

	/**
	 * @author cbra
	 */
	public class Ball3D extends SpriteWrapper {

		private static const CAM_DISTANCE_FACTOR:int = 100000;
		private static const CONVERSION_FACTOR:Number = 0.05;
		private var world3D:Scene3D;
		private var library:Library;
		private var camera:Camera3D;
		private var scene3D:Group;
		private var ballGroup:Group;
		private var ballModel:Sphere;
		private var id:String;
		private var container:Sprite;	
		private var _rotation:Quaternion;
		private var _oldPosition:Vector;
		


		public function Ball3D(aId:String, aContainer:Sprite) {
			super( Library.getInstance().createClip("ball"));
			library = Library.getInstance();
//			ballSprite = library.createClip("ball");
			container = aContainer;
			container.addChild(_sprite);
			_sprite.x = 200;
			_sprite.y = 200;
			_oldPosition = new Vector(_sprite.x,_sprite.y);
			_sprite.width = 20;
			_sprite.height = 20;
			_rotation = new Quaternion();
			id = aId;
			createWorld();
			world3D.render();	
		}
		
		public function update(event:Event = null):void {
//			Debug.trace("onMouseMove x "+_sprite.x+" y: "+ _sprite.y);
			var newPosition:Vector = new Vector(_sprite.x,_sprite.y);
			var diffVector:Vector = newPosition.minus(_oldPosition);
			convertTranslationToAngleShift(diffVector);
			_rotation.toSandyRotationMatrix(ballModel.matrix);
			world3D.render();	
			_oldPosition = newPosition;
		}
		
		// creates the 3D world of the ballModel
		private function createWorld():void{		
			world3D  = new Scene3D(null, null, null, null );
			world3D.container = _sprite.getChildByName("container") as Sprite;
			camera =  new Camera3D(260,260,45/CAM_DISTANCE_FACTOR,50,100000000);
 			world3D.camera = camera;
			scene3D = new Group("scene");
			scene3D.addChild(world3D.camera);
			ballGroup = new Group("balls");
			scene3D.addChild(ballGroup);
			world3D.root = scene3D;	
			
			ballModel = createBall(20,20);
				
			ballGroup.addChild(ballModel);	
			camera.z = 70 * CAM_DISTANCE_FACTOR;					
			camera.lookAt(ballModel.x, ballModel.y, ballModel.z);		
		}
		
		// creates the 3D representation of the ball
		private function createBall(wSegments:int,hSegments:int):Sphere{	
			var ballBitmapData:BitmapData = library.createBitmapData(id, 1, 1);
			var material:Material = new BitmapMaterial(ballBitmapData);
			
			var newBallall:Sphere = new Sphere(id,11,wSegments,hSegments);
			newBallall.useSingleContainer = true;		
			newBallall.container.x = -130;
			newBallall.container.y = -130;
			newBallall.appearance = new Appearance( material);	
			return newBallall;				
		}
		
		/**
		 * ROLL FX 
		 * 
		 * params: Vector deltaMove, Quat4 currentRotation, Number conversionFactor
		 * return: Quat4 resultRotation
		 */
		public function convertTranslationToAngleShift(move:Vector):void {		
			// convert translation to move
			if (move.magnitude() > 0.00001) {
				// calc roll axis
				var rollAngle:Number = move.magnitude() * CONVERSION_FACTOR;
				//var rollAxis:Vector = move.normalize().rotate90CCW();
			    var rollAxis:Vector = move.rotate(rollAngle);
			
				// get axis rotation as quat
				var currentAxisRotation:Quaternion = new Quaternion();
				getAxisRotationAsQuaternion(currentAxisRotation, new Vector3f(rollAxis.x, rollAxis.y, 0), rollAngle);
//			getAxisRotationAsQuaternion(currentAxisRotation, new Vector3f(move.x, move.y, 0), rollAngle);
			
				// connect rotation in worldcoordinates
				_rotation = currentAxisRotation.connect(_rotation);
			}
			// use old rotation
			else {
				_rotation = _rotation.clone();	
			}
		}
		
		public function getAxisRotationAsQuaternion( q:Quaternion, axis:Vector3f, angle:Number):void {
			var d:Number = axis.length();

			if(d == 0) {
				throw new IllegalOperationError("d must not be zero!");
			}
			
			var s:Number = Math.sin(angle * 0.5) / d;
			q.set(axis.x * s, axis.y * s, axis.z * s, Math.cos(angle * 0.5));
		}
		
	}
	
}
